﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace AT.IBMS.Framework.Tools
{
    public static class CryptographyTool
    {

        private static string ENCRYPT_KEY = "AT_IBMS_Framework_Tools_CryptographyTool_Encrypt_Key";

        /// <summary>
        /// md5加密为一个不可逆的密文。
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static string EncryptPassword(this Tool t, string text, bool doubleEncrypt = true)
        {

            //双重加密。md5(md5(text) + text)

            string plaintext;
            Byte[] clearBytes;
            Byte[] hashedBytes;

            plaintext = text;

            if (doubleEncrypt)
            {
                clearBytes = new UnicodeEncoding().GetBytes(text);
                hashedBytes = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(clearBytes);
                plaintext = BitConverter.ToString(hashedBytes);
                plaintext = plaintext + text;
            }

            clearBytes = new UnicodeEncoding().GetBytes(plaintext);
            hashedBytes = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(clearBytes);
            return BitConverter.ToString(hashedBytes);

        }

        /// <summary>
        /// 为文本加密。
        /// </summary>
        /// <param name="t"></param>
        /// <param name="plaintext">要加密的文本。</param>
        /// <param name="key">秘钥。可以为空，则有架构指定默认秘钥。</param>
        /// <returns>加密后的密文。</returns>
        public static string EncryptText(this Tool t, string plaintext, string key = null)
        {
            byte[] data;
            AesManaged aes;
            string keyValue;
            ICryptoTransform encryptTransform;
            MemoryStream encryptStream;
            CryptoStream encryptor;
            string encryptedString;

            keyValue = key;

            if (string.IsNullOrWhiteSpace(keyValue))
            {
                keyValue = ENCRYPT_KEY;
            }

            data = Encoding.UTF8.GetBytes(plaintext);
            aes = CreateAesManaged(keyValue);

            //用当前的 Key 属性和初始化向量 IV 创建对称加密器对象
            encryptTransform = aes.CreateEncryptor();

            //加密后的输出流
            using (encryptStream = new MemoryStream())
            {

                //将加密后的目标流（encryptStream）与加密转换（encryptTransform）相连接
                using (encryptor = new CryptoStream(encryptStream, encryptTransform, CryptoStreamMode.Write))
                {
                    //将一个字节序列写入当前 CryptoStream （完成加密的过程）
                    encryptor.Write(data, 0, data.Length);
                }

                encryptedString = Convert.ToBase64String(encryptStream.ToArray());

            }


            return encryptedString;

        }

        /// <summary>
        /// 为文本解密。
        /// </summary>
        /// <param name="t"></param>
        /// <param name="encryptedtext">要解密的密文。</param>
        /// <param name="key">秘钥。可以为空，则有架构指定默认秘钥。</param>
        /// <returns>解密后的明文。</returns>
        public static string DecryptText(this Tool t, string encryptedtext, string key = null)
        {

            string keyValue;
            byte[] encryptBytes;
            byte[] decryptBytes;
            AesManaged aes;
            ICryptoTransform decryptTransform;
            MemoryStream decryptStream;
            CryptoStream decryptor;
            string decryptedString;

            keyValue = key;

            if (string.IsNullOrWhiteSpace(keyValue))
            {
                keyValue = ENCRYPT_KEY;
            }

            encryptBytes = Convert.FromBase64String(encryptedtext);
            aes = CreateAesManaged(keyValue);
            decryptTransform = aes.CreateDecryptor();

            using (decryptStream = new MemoryStream())
            {

                using (decryptor = new CryptoStream(decryptStream, decryptTransform, CryptoStreamMode.Write))
                {
                    decryptor.Write(encryptBytes, 0, encryptBytes.Length);
                }

                decryptBytes = decryptStream.ToArray();
                decryptedString = Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
            }

            return decryptedString;

        }

        private static AesManaged CreateAesManaged(string key)
        {

            byte[] salt;
            AesManaged aes;
            Rfc2898DeriveBytes rfc;

            salt = Encoding.UTF32.GetBytes(CreateKey(key));

            aes = new AesManaged();
            rfc = new Rfc2898DeriveBytes(key, salt);

            //aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
            //aes.KeySize = aes.LegalKeySizes[0].MaxSize;
            aes.Key = rfc.GetBytes(aes.KeySize / 8);
            aes.IV = rfc.GetBytes(aes.BlockSize / 8);

            return aes;
        }

        private static string CreateKey(string key)
        {

            byte[] bytes;

            bytes = Encoding.UTF32.GetBytes(key);

            if (bytes.Length < 8)
            {
                return CreateKey(key + 0x00);
            }
            else
            {
                return key;
            }

        }

    }
}
